﻿module temp

#light

open System



let Mod x = if x % 3 = 0 then true
              elif x % 5  = 0 then true
              else false


let seq = [1 .. 999]
let result_p1 = 
    seq |> Seq.fold (fun acc x -> 
                if Mod x then acc + x
                else acc) 0

let result_p2 = //4613732
    let resultseq = Seq.unfold (fun (a0, a1) -> 
                                    if a0 <= 4000000 then Some(a0, (a1, a0 + a1))
                                    else None) (1, 2)
    resultseq |> Seq.fold (fun acc x -> if x % 2 = 0 then acc + x
                                        else acc) 0


let result_p3 = //6857
    let bigint = 600851475143L
    let IsPrime x = 
        let rootx = sqrt (float x)
        let dividers = List.filter (fun i -> i % 2 = 1) [3 .. (int rootx)]
        let dividerset = [2] @ dividers
        not (dividerset |> List.exists (fun i -> x % i = 0))
    let primeseq = List.filter IsPrime [1..800000]
    primeseq |> Seq.fold (fun res x -> if bigint % (int64 x) = (int64 0) then x
                                        else res) 1

let result_p4 = //906609
    let RevList list = List.fold (fun acc elem -> elem::acc) [] list
    let RevStr (s:string) = new string(Array.rev (s.ToCharArray()))
    let IsPL x = 
        let strx = x.ToString()
        strx.Equals(RevStr strx)
    let Dividable bigint = 
        let bottom = bigint / 1000 + 1
        let testers = [bottom .. 999]
        testers |> List.exists (fun x -> if bigint % x = 0 then printfn "%d" x 
                                                                true
                                         else false)
    let PLcdds = 
        let all = [900000..950000]                               //needs to try here
        let revall = RevList all
        List.filter IsPL revall
    List.find Dividable PLcdds

let result_p5 = //232792560
    let rec gcd a b = 
        if a % b = 0 then b
        else gcd b (a % b)            //caution: stack overflow
    let lcm list = 
        Seq.fold (fun acc x -> acc * (x / (gcd acc x))) 1 list
    lcm [1..20]

let result_p6 = //-25164150
    let sumsq list = 
        Seq.fold (fun acc x -> acc + x * x) 0 list
    let sqsum list = 
        let sum = Seq.fold (fun acc x -> acc + x) 0 list
        sum * sum
    sumsq [1..100] - sqsum [1..100]

let result_p7 = //104759
    let primeli = [2]
    let res = Seq.unfold (fun (x, list) -> 
        if Seq.length list > 10001 then 
            None
        else 
            if (Seq.exists (fun x1 -> x % x1 = 0) list) then //not a prime
                Some(0, (x + 2, list))
            else //a prime
                Some(x, (x + 2, list @ [x]))) (3, primeli)
    let resfilter = res |> Seq.filter (fun x -> x <> 0)
    let resfinal = 2 :: Seq.toList resfilter
    printfn "%d" resfinal.[10000]//(Seq.nth 10000 resfinal)

let result_p8 = //40824
    let strNum = "73167176531330624919225119674426574742355349194934\
                  96983520312774506326239578318016984801869478851843\
                  85861560789112949495459501737958331952853208805511\
                  12540698747158523863050715693290963295227443043557\
                  66896648950445244523161731856403098711121722383113\
                  62229893423380308135336276614282806444486645238749\
                  30358907296290491560440772390713810515859307960866\
                  70172427121883998797908792274921901699720888093776\
                  65727333001053367881220235421809751254540594752243\
                  52584907711670556013604839586446706324415722155397\
                  53697817977846174064955149290862569321978468622482\
                  83972241375657056057490261407972968652414535100474\
                  82166370484403199890008895243450658541227588666881\
                  16427171479924442928230863465674813919123162824586\
                  17866458359124566529476545682848912883142607690042\
                  24219022671055626321111109370544217506941658960408\
                  07198403850962455444362981230987879927244284909188\
                  84580156166097919133875499200524063689912560717606\
                  05886116467109405077541002256983155200055935729725\
                  71636269561882670428252483600823257530420752963450"
    let atoi i = 
        match i with
        |'0' -> 0
        |'1' -> 1
        |'2' -> 2
        |'3' -> 3
        |'4' -> 4
        |'5' -> 5
        |'6' -> 6
        |'7' -> 7
        |'8' -> 8
        |'9' -> 9
        | _  -> -1
    let prod i numli = 
        if i < 2 then 0
        elif i > (List.length numli - 3) then 0
        else numli.[i - 2] * numli.[i - 1] * numli.[i] * numli.[i + 1] * numli.[i + 2]
    let MaxProd numli = 
        let newli = 
            let len = List.length numli
            printfn "length:%d" len
            List.mapi (fun i x -> if i < 2 then 0
                                  elif i > (len - 3) then 0
                                  else numli.[i - 2] * numli.[i - 1] * x * numli.[i + 1] * numli.[i + 2]) numli
        List.max newli
    let strli = [for i in 0..(String.length strNum - 1) -> (atoi strNum.[i])]
    strli |> MaxProd
    //needs improvement

let result_p9 = //31875000
    let gotcha (c:int) :bool = 
        let a_b = 1000 - c
        List.exists (fun x -> (a_b - x) * (a_b - x) + 
                                      x * x = c * c) [1 .. (a_b - 1)]
    let RevList list = List.fold (fun acc elem -> elem::acc) [] list
    let ccdd = [334..499]
    let ccddr = RevList ccdd
    let l = List.find gotcha ccddr
    printfn "%d" l
    let a_b = 1000 - l
    let a = List.find (fun x -> (a_b - x) * (a_b - x) + 
                                      x * x = l * l) [1 .. (a_b - 1)]
    let b = 1000 - a - l
    a * b * l

let result_p10 = //142913828922L
    let res = Seq.unfold (fun (x, list) -> 
        if x > 1500 then 
            None
        else 
            if (Seq.exists (fun x1 -> x % x1 = 0) list) then //not a prime
                Some(0, (x + 2, list))
            else //a prime
                Some(x, (x + 2, list @ [x]))) (3, [2])
    let resfilter = res |> Seq.filter (fun x -> x <> 0)
    let resfinal = 2 :: Seq.toList resfilter
    [3 .. 2000000] |> List.fold (fun acc x -> if x % 2 = 0 then acc
                                                elif List.exists (fun x1 -> x % x1 = 0) 
                                                     (List.filter (fun i -> i <= (int (sqrt (float x)))) resfinal) then acc
                                                else acc + (int64 x)) 2L 

let result_p11 = //70600674
    let arrBase = array2D [[08; 02; 22; 97; 38; 15; 00; 40; 00; 75; 04; 05; 07; 78; 52; 12; 50; 77; 91; 08]; 
                      [49; 49; 99; 40; 17; 81; 18; 57; 60; 87; 17; 40; 98; 43; 69; 48; 04; 56; 62; 00]; 
                      [81; 49; 31; 73; 55; 79; 14; 29; 93; 71; 40; 67; 53; 88; 30; 03; 49; 13; 36; 65]; 
                      [52; 70; 95; 23; 04; 60; 11; 42; 69; 24; 68; 56; 01; 32; 56; 71; 37; 02; 36; 91]; 
                      [22; 31; 16; 71; 51; 67; 63; 89; 41; 92; 36; 54; 22; 40; 40; 28; 66; 33; 13; 80]; 
                      [24; 47; 32; 60; 99; 03; 45; 02; 44; 75; 33; 53; 78; 36; 84; 20; 35; 17; 12; 50]; 
                      [32; 98; 81; 28; 64; 23; 67; 10; 26; 38; 40; 67; 59; 54; 70; 66; 18; 38; 64; 70]; 
                      [67; 26; 20; 68; 02; 62; 12; 20; 95; 63; 94; 39; 63; 08; 40; 91; 66; 49; 94; 21]; 
                      [24; 55; 58; 05; 66; 73; 99; 26; 97; 17; 78; 78; 96; 83; 14; 88; 34; 89; 63; 72]; 
                      [21; 36; 23; 09; 75; 00; 76; 44; 20; 45; 35; 14; 00; 61; 33; 97; 34; 31; 33; 95]; 
                      [78; 17; 53; 28; 22; 75; 31; 67; 15; 94; 03; 80; 04; 62; 16; 14; 09; 53; 56; 92]; 
                      [16; 39; 05; 42; 96; 35; 31; 47; 55; 58; 88; 24; 00; 17; 54; 24; 36; 29; 85; 57]; 
                      [86; 56; 00; 48; 35; 71; 89; 07; 05; 44; 44; 37; 44; 60; 21; 58; 51; 54; 17; 58]; 
                      [19; 80; 81; 68; 05; 94; 47; 69; 28; 73; 92; 13; 86; 52; 17; 77; 04; 89; 55; 40]; 
                      [04; 52; 08; 83; 97; 35; 99; 16; 07; 97; 57; 32; 16; 26; 26; 79; 33; 27; 98; 66]; 
                      [88; 36; 68; 87; 57; 62; 20; 72; 03; 46; 33; 67; 46; 55; 12; 32; 63; 93; 53; 69]; 
                      [04; 42; 16; 73; 38; 25; 39; 11; 24; 94; 72; 18; 08; 46; 29; 32; 40; 62; 76; 36]; 
                      [20; 69; 36; 41; 72; 30; 23; 88; 34; 62; 99; 69; 82; 67; 59; 85; 74; 04; 36; 16]; 
                      [20; 73; 35; 29; 78; 31; 90; 01; 74; 31; 49; 71; 48; 86; 81; 16; 23; 57; 05; 54]; 
                      [01; 70; 54; 71; 83; 51; 54; 69; 16; 92; 33; 48; 61; 43; 52; 01; 89; 19; 67; 48]]
    let arrRes = Array2D.zeroCreate 20 20
    let calcH x y value = value * arrBase.[x + 1, y] * arrBase.[x + 2, y] * arrBase.[x + 3, y] 
    let calcV x y value = value * arrBase.[x, y + 1] * arrBase.[x, y + 2] * arrBase.[x, y + 3] 
    let calcR x y value = value * arrBase.[x + 1, y + 1] * arrBase.[x + 2, y + 2] * arrBase.[x + 3, y + 3] 
    let calcL x y value = value * arrBase.[x - 1, y + 1] * arrBase.[x - 2, y + 2] * arrBase.[x - 3, y + 3] 
    let calc x y value mode = 
        match mode with
        | 4 -> List.max [calcV x y value; calcH x y value; calcR x y value; calcL x y value]
        | 3 -> List.max [calcV x y value; calcH x y value; calcR x y value]
        | 2 -> List.max [calcV x y value; calcL x y value]
        | 1 -> List.max [calcH x y value]
        | 0 -> -1
        | _ -> -1
    let iterfun x y value = 
        match (x, y) with
        |(x, y) when x <= 3 && y <= 16            -> arrRes.[x, y] <- calc x y value 3
        |(x, y) when x <= 16 && x >= 4 && y <= 16 -> arrRes.[x, y] <- calc x y value 4
        |(x, y) when x >= 16 && y <= 16           -> arrRes.[x, y] <- calc x y value 2
        |(x, y) when x <= 16 && y >= 17           -> arrRes.[x, y] <- calc x y value 1
        |(x, y) when x = 19 && y = 19             -> printf "%d" arrRes.[19, 19]
        | _                                       -> arrRes.[x, y] <- calc x y value 0
        if arrRes.[19, 19] < arrRes.[x, y] then arrRes.[19, 19] <- arrRes.[x, y]
    arrBase |> Array2D.iteri iterfun

let result_12 = //76576500
    let divisorCount num = 
        if num % 2 <> 0 then
            [1..(num / 2)] |> List.fold (fun acc x -> if num % x = 0 then acc + 1
                                                      else acc) 1
        else
            let num2 = num / 2
            [1..(num2 / 2)] |> List.fold (fun acc x -> if num2 % x = 0 then acc + 1
                                                       else acc) 1
    let triNum = Seq.unfold (fun x -> if ((divisorCount x) * (divisorCount (x + 1))) > 500 then None
                                      else Some(x, x + 1)) 1//or bigger is okay
    let factor = (Seq.nth (Seq.length triNum - 1) triNum) + 1
    (factor + 1) * factor / 2

let result_p13 = //5537376230
    let strNum = ["37107287533902102798797998220837590246510135740250";
                          "46376937677490009712648124896970078050417018260538";
                          "74324986199524741059474233309513058123726617309629";
                          "91942213363574161572522430563301811072406154908250";
                          "23067588207539346171171980310421047513778063246676";
                          "89261670696623633820136378418383684178734361726757";
                          "28112879812849979408065481931592621691275889832738";
                          "44274228917432520321923589422876796487670272189318";
                          "47451445736001306439091167216856844588711603153276";
                          "70386486105843025439939619828917593665686757934951";
                          "62176457141856560629502157223196586755079324193331";
                          "64906352462741904929101432445813822663347944758178";
                          "92575867718337217661963751590579239728245598838407";
                          "58203565325359399008402633568948830189458628227828";
                          "80181199384826282014278194139940567587151170094390";
                          "35398664372827112653829987240784473053190104293586";
                          "86515506006295864861532075273371959191420517255829";
                          "71693888707715466499115593487603532921714970056938";
                          "54370070576826684624621495650076471787294438377604";
                          "53282654108756828443191190634694037855217779295145";
                          "36123272525000296071075082563815656710885258350721";
                          "45876576172410976447339110607218265236877223636045";
                          "17423706905851860660448207621209813287860733969412";
                          "81142660418086830619328460811191061556940512689692";
                          "51934325451728388641918047049293215058642563049483";
                          "62467221648435076201727918039944693004732956340691";
                          "15732444386908125794514089057706229429197107928209";
                          "55037687525678773091862540744969844508330393682126";
                          "18336384825330154686196124348767681297534375946515";
                          "80386287592878490201521685554828717201219257766954";
                          "78182833757993103614740356856449095527097864797581";
                          "16726320100436897842553539920931837441497806860984";
                          "48403098129077791799088218795327364475675590848030";
                          "87086987551392711854517078544161852424320693150332";
                          "59959406895756536782107074926966537676326235447210";
                          "69793950679652694742597709739166693763042633987085";
                          "41052684708299085211399427365734116182760315001271";
                          "65378607361501080857009149939512557028198746004375";
                          "35829035317434717326932123578154982629742552737307";
                          "94953759765105305946966067683156574377167401875275";
                          "88902802571733229619176668713819931811048770190271";
                          "25267680276078003013678680992525463401061632866526";
                          "36270218540497705585629946580636237993140746255962";
                          "24074486908231174977792365466257246923322810917141";
                          "91430288197103288597806669760892938638285025333403";
                          "34413065578016127815921815005561868836468420090470";
                          "23053081172816430487623791969842487255036638784583";
                          "11487696932154902810424020138335124462181441773470";
                          "63783299490636259666498587618221225225512486764533";
                          "67720186971698544312419572409913959008952310058822";
                          "95548255300263520781532296796249481641953868218774";
                          "76085327132285723110424803456124867697064507995236";
                          "37774242535411291684276865538926205024910326572967";
                          "23701913275725675285653248258265463092207058596522";
                          "29798860272258331913126375147341994889534765745501";
                          "18495701454879288984856827726077713721403798879715";
                          "38298203783031473527721580348144513491373226651381";
                          "34829543829199918180278916522431027392251122869539";
                          "40957953066405232632538044100059654939159879593635";
                          "29746152185502371307642255121183693803580388584903";
                          "41698116222072977186158236678424689157993532961922";
                          "62467957194401269043877107275048102390895523597457";
                          "23189706772547915061505504953922979530901129967519";
                          "86188088225875314529584099251203829009407770775672";
                          "11306739708304724483816533873502340845647058077308";
                          "82959174767140363198008187129011875491310547126581";
                          "97623331044818386269515456334926366572897563400500";
                          "42846280183517070527831839425882145521227251250327";
                          "55121603546981200581762165212827652751691296897789";
                          "32238195734329339946437501907836945765883352399886";
                          "75506164965184775180738168837861091527357929701337";
                          "62177842752192623401942399639168044983993173312731";
                          "32924185707147349566916674687634660915035914677504";
                          "99518671430235219628894890102423325116913619626622";
                          "73267460800591547471830798392868535206946944540724";
                          "76841822524674417161514036427982273348055556214818";
                          "97142617910342598647204516893989422179826088076852";
                          "87783646182799346313767754307809363333018982642090";
                          "10848802521674670883215120185883543223812876952786";
                          "71329612474782464538636993009049310363619763878039";
                          "62184073572399794223406235393808339651327408011116";
                          "66627891981488087797941876876144230030984490851411";
                          "60661826293682836764744779239180335110989069790714";
                          "85786944089552990653640447425576083659976645795096";
                          "66024396409905389607120198219976047599490197230297";
                          "64913982680032973156037120041377903785566085089252";
                          "16730939319872750275468906903707539413042652315011";
                          "94809377245048795150954100921645863754710598436791";
                          "78639167021187492431995700641917969777599028300699";
                          "15368713711936614952811305876380278410754449733078";
                          "40789923115535562561142322423255033685442488917353";
                          "44889911501440648020369068063960672322193204149535";
                          "41503128880339536053299340368006977710650566631954";
                          "81234880673210146739058568557934581403627822703280";
                          "82616570773948327592232845941706525094512325230608";
                          "22918802058777319719839450180888072429661980811197";
                          "77158542502016545090413245809786882778948721859617";
                          "72107838435069186155435662884062257473692284509516";
                          "20849603980134001723930671666823555245252804609722";
                          "53503534226472524250874054075591789781264330331690"]
    let atoi i = 
        match i with
        |'0' -> 0
        |'1' -> 1
        |'2' -> 2
        |'3' -> 3
        |'4' -> 4
        |'5' -> 5
        |'6' -> 6
        |'7' -> 7
        |'8' -> 8
        |'9' -> 9
        | _  -> -1
    let str2iarray (s:string) = 
        let charr = s.ToCharArray()
        Array.map atoi charr
    let numbers = Array2D.init 100 50 (fun x y -> (str2iarray strNum.[x]).[y])
    let addColumn index = 
        if index > 50 then 0
        else let column = 
                Array.init 100 (fun x -> numbers.[x, 50 - index])
             column |> Array.sum
    let result = Seq.unfold (fun (cur, (c_a1, c_a2, c_b1, c_b2)) ->                    //cur is from 1 to 52
                             if cur > 52 then None
                             else
                                let colsum = (addColumn cur) + c_a2 + c_b1
                                let value = colsum % 10
                                let c2 = colsum / 100
                                let c1 = (colsum % 100) / 10
                                Some(value, (cur + 1, (c_b1, c_b2, c1, c2)))) 
                             (1, (0, 0, 0, 0))
    let reslist = Seq.toList result
    //let sumten = (result |> Seq.mapi (fun i x -> if i < 42 then 0
    //                                             else x)) |> Seq.fold (fun acc x -> acc + x) 0
    //printfn "%d" sumten
    printfn "%A" reslist

let result_p14 = //again, must use 64bit int, 837799 length 525
    let lowb = 10000L
    let hib = 999999L
    let ValueArr = Array.init ((int hib) - (int lowb)) (fun i -> lowb + (int64 i))
    let seql start = 
        let seqi = Seq.unfold (fun x -> if x < hib && x >= lowb && x <> start then ValueArr.[(int x) - (int lowb)] <- -1L //add this value to a set to filter
                                        if x = 1L then None
                                        elif x % 2L = 0L then Some(x, x / 2L)
                                        else Some(x, x * 3L + 1L)) start
        ValueArr.[(int start) - (int lowb)] <- (int64 (Seq.length seqi)) + 1L
    ValueArr |> Array.iter (fun x ->   if x = -1L then ()
                                       else seql x)
    let longest = ValueArr |> Array.max
    let longind = ValueArr |> Array.findIndex (fun x -> x = longest)
    printfn "%d :: %d" longest (longind + (int lowb))

let result_p15 = //137846528820, cannot calc this with f#, use Python instead
    let foldmul s e = [e..s] |> List.fold (fun acc x -> acc * x) 1L
    let C p1 p2 = (foldmul p2 (p2 - p1 + 1L)) / (foldmul p1 1L)
    C 20L 40L

let result_p16 = 
    



    //printfn "%d" primeli.[10000]

    //List.fold (+) 0 [2;3;4]
    
;;
